#include"pool.h"


/*函数指针的调用方式
  void （*fd）（int）=fun
    1.fd(1)
    2.(*fd)(1)
    注意：
        1.使用条件变量前，需要先初始化，可以使用pthread_cond_init。
        2.不再使用时，应使用pthread_cond_destroy销毁条件变量。
        3.虽然pthread_cond_wait在等待时会释放互斥锁，但在被唤醒并从pthread_cond_wait返回时，它会再次获得该锁。
        4.由于存在所谓的"虚假唤醒"（spurious wakeup），线程在被唤醒后应该再次检查条件是否真的满足，这也是为什么通常在while循环中检查条件。
        5.总的来说，条件变量提供了一种方式，允许线程在某些条件成立前休眠，并在条件成立后被唤醒，从而实现复杂的同步需求。
*/

/*4.资源回收
thread_pool *pool
*/
void threadpool_destry(thread_pool* pool)
{
    pool->running=1;
    pthread_cond_broadcast(&(pool->queue_empty));   //广播通知条件变量发生变化
    pthread_cond_destroy(&(pool->queue_empty));
    pthread_cond_destroy(&(pool->queue_full));      //回收环境变量

    while(pthread_mutex_destroy(&(pool->mutex))!=0);    //互斥锁在未解锁的时候无法释放

    int i;
    for(i=0;i<(pool->thread_num);i++)
    {
        if(pthread_join(pool->id[i],NULL)!=0)
        {
            printf("%d回收失败",(int)pool->id[i]);
        }
    }
    free(pool->id);
    //printf("回收成功\n");
    task *p=pool->head,*q=NULL;
    while(p)
    {
        //printf("回收成功\n");
        q=p;
        p=p->next;
        free(q);
    }
    pool->head=pool->tail=NULL;
    pool->id=NULL;
    return ;
}

/*3.线程执行函数*/
void* thread_fun(void* agrp)
{
    thread_pool* pool =(thread_pool*)agrp;
    task* p = NULL;
    while(1)
    {
        pthread_mutex_lock(&(pool->mutex));                         //条件变量必须和互斥锁联合使用
        while(pool -> queue_num == 0 && (pool->running == 0))                               //任务为零时
        {
            pthread_cond_wait(&(pool->queue_empty),&(pool->mutex)); //当条件变量不满足条件时，会使得线程进入等待，并且释放互斥锁，当条件变量发送变化时
            //重新获得互斥锁
        }
        if(pool->running==1)                       //所有任务完成后结束线程池
        {
            pthread_mutex_unlock(&(pool->mutex));
            break;
        }
        p = pool -> head;                                           //拿到任务的头
        (pool->queue_num)--;
        if(pool -> queue_num == 0)
        {
            pool-> head = pool-> tail = NULL;
        }
        else 
        { 
            pool-> head = p-> next;
        }
        if(pool -> queue_num == pool ->queue_max_size -1)
        {
            pthread_cond_signal(&(pool->queue_full));
        }
         pthread_mutex_unlock(&(pool->mutex));
        (*(p->fun))(p->argp);
        free(p);
        p=NULL;
       
    }

    return NULL;
}

/*2.任务添加*/
int task_add(thread_pool* pool,void* (*fun)(void*),void* argp)
{
    if(pool ==NULL || fun==NULL)
    {
        printf("传入的线程池or任务函数指针为空,\n");
        return -1;
    }
    pthread_mutex_lock(&(pool->mutex));
    while(pool->queue_num==pool->queue_max_size)                //当任务队列满时，用任务添加阻塞条件变量阻塞
    {
        pthread_cond_wait(&(pool->queue_full),&(pool->mutex));  
    }
    task *p=(task*)malloc(sizeof(task));                        //为一个任务节点开辟空间
    if(p==NULL)
    {
        pthread_mutex_unlock(&(pool->mutex));
        return -1;
    }
    p->fun=fun;
    p->argp=argp;
    p->next=NULL;

    if(pool->tail==NULL)                        //代表任务队列空队                                           
    {    
        pool->head=pool->tail=p;                //跟新头位指针位p的地址
        pthread_cond_broadcast(&(pool->queue_empty));           //通知所有条件变量重新判定，是否为空
    }
    else
    {                                       //任务队列不为空时
        pool->tail->next=p;                    //根系尾节点的next
        pool->tail=p;                          //尾节点更新为p的地址
    }
    (pool->queue_num)++;                       
    pthread_mutex_unlock(&(pool->mutex));
    
    return 0;
}


/*1.线程池创建*/
int threadpool_init(thread_pool* pool,int tnum,int qsize)
{
    pool-> thread_num = tnum;       //线程中开启的线程数
    pool-> queue_num  = 0;          //任务数
    pool-> queue_max_size = qsize;  //任务队列最大容量
    pool-> head = pool->tail = NULL;      //任务队列头尾
    pool->running = 0;

    if(pthread_mutex_init(&(pool->mutex),NULL))         //创建互斥锁
    {
        return -1;
    }
    if(pthread_cond_init(&(pool->queue_empty),NULL))    //创建队列为空的条件变量
    {
        pthread_mutex_destroy(&(pool->mutex));
        return -1;
    }
    if(pthread_cond_init(&(pool->queue_full),NULL))     //创建队列满的条件变量
    {
        pthread_mutex_destroy(&(pool->mutex));
        pthread_cond_destroy(&(pool->queue_empty));
        return -1;
    }
    pool-> id = (pthread_t*)malloc(sizeof(pthread_t)*tnum);
    if(pool->id == NULL)
    {
        pthread_mutex_destroy(&(pool-> mutex));
        pthread_cond_destroy(&(pool->queue_empty));
        pthread_cond_destroy(&(pool->queue_full));
        return -1;
    }

    for(register int i = 0;i < tnum; i++)
    {
        pthread_create(&(pool->id[i]),NULL,thread_fun,pool);
    }


    return 0;
}